﻿using System;
using System.Linq;

namespace HQS.TokenInterpolation
{
    public abstract class AbstractToken : IVisitable
    {
        public string TokenExpressionName
        {
            get
            {
                TokenAttribute att =
                    GetType().GetCustomAttributes(typeof (TokenAttribute), false).FirstOrDefault() as TokenAttribute;
                return att == null ? string.Empty : att.Name;
            }
        }

        public string OriginalText { get; set; }

        public virtual bool AutoBind
        {
            get { return true; }
        }

        public int StartIndex { get; set; }

        public int EndIndex { get; set; }

        public string Name { get; set; }

        /// <summary>
        ///     This property will indicate if the token can have tokens nested inside its context
        /// </summary>
        public virtual bool AllowNestingTokens
        {
            get { return true; }
        }

        /// <summary>
        ///     This entry will be display when the Token have an Error Message
        /// </summary>
        [TokenProperty("error", false)]
        public string IfErrorUse { get; set; }

        /// <summary>
        ///     This method is called before Validate.
        ///     It gives child classes a chance to validate context using OriginalText.
        /// </summary>
        public void Init()
        {
            OnInit();
        }

        /// <summary>
        ///     This is called by the Parser to parse token.
        /// </summary>
        /// <param name="context"></param>
        /// <returns>TokenRuntimeValue instance</returns>
        public TokenRuntimeValue Accept(IDataSourcesVisitor context)
        {
            return OnAccept(context);
        }

        /// <summary>
        ///     This is called to Validate a context.
        /// </summary>
        /// <returns>null/empty for validate tokens. Otherwise, an error message</returns>
        public string ValidateContext()
        {
            return OnValidateContext();
        }

        protected virtual string OnValidateContext()
        {
            return null;
        }

        /// <summary>
        ///     Override this method if you want the derived class to take over parsing the context.
        /// </summary>
        protected virtual void OnInit()
        {
        }

        protected abstract TokenRuntimeValue OnAccept(IDataSourcesVisitor context);
    }
}